#pragma once

#include "../Common/Common.h"
#include "../Thread/PosixThreads.h"
#include <ctime>

const int MAIN_DATABUFFER_LENGTH = 100;
//const int MAIN_DATABUFFER_LENGTH = 3;

class PSDF_CORE_DLL_DECL DataCenter
{

private:

	//-----------------------------------------
	// ReferencedData
	//-----------------------------------------
	struct ReferencedData
	{
		clock_t timestamp;
		int refCount;
		int bufferLength;
		int dataLength;
		char* buffer;

		ReferencedData():
		timestamp(0), refCount(0), bufferLength(0), dataLength(0), buffer(NULL) {}
	};
	//------------------------------------------

public:

	//-----------------------------------
	// DataPtr
	//-----------------------------------
	template<typename T>
	class DataPtr
	{
	public:
		DataPtr() { _refData = NULL; _ptr = NULL; }
		DataPtr(const DataPtr& dataPtr)
		{
			if (dataPtr._refData)
			{
				this->_refData = dataPtr._refData;
				this->_ptr = dataPtr._ptr;
				_refData->refCount++;
			}
		}
		~DataPtr()
		{
			if (_refData) { _refData->refCount--; _refData->timestamp = clock(); }
		}

		// pointer operations
		T& operator*() const { return *_ptr; }
		T* operator->() const { return _ptr; }
		T* get() const { return _ptr; }

		// bool operations
		operator T*() { return _ptr; }
		bool operator==(const DataPtr& dataPtr) const { return this->_ptr == dataPtr._ptr; }
		bool operator==(const T* ptr) const { return this->_ptr == ptr; }
		friend bool operator==(const T* ptr, const DataPtr& dataPtr) { return ptr == dataPtr._ptr; }
		bool operator!=(const DataPtr& dataPtr) const { return this->_ptr != dataPtr._ptr; }
		bool operator!=(const T* ptr) const { return this->_ptr != ptr; }
		friend bool operator!=(const T* ptr, const DataPtr& dataPtr) { return ptr != dataPtr._ptr; }

		void assign(ReferencedData& refData)
		{
			if (_refData) { _refData->refCount--; }
			_refData = &refData;
			_ptr = (T*)(_refData->buffer);
			_refData->refCount++;
		}

	private:
		ReferencedData* _refData;
		T*				_ptr;

	};
	//--------------------------------------------



	//----------------------------------------------
	// MemoryReleaser :
	// release buffer memory for every few seconds
	//----------------------------------------------
	class MemoryReleaser : public PosixThread
	{
	public:
		void run();
		
		void clearMainBuffer();
		void clearAssistBuffer();

		DataCenter*	_center;
		bool		_shouldQuit;
	};

private:
	DataCenter();
	DataCenter(const DataCenter&) {}
	~DataCenter();

public:
	static DataCenter*	inst();

	// return dataIndex
	int	addData(char* data, int length);

	template<typename T>
	void getData(DataPtr<T>& dataPtr, unsigned int dataIndex)
	{
		if (dataIndex < MAIN_DATABUFFER_LENGTH)
		{
			if (_mainDataBuffer[dataIndex].buffer == NULL) { return; }
			dataPtr.assign(_mainDataBuffer[dataIndex]);
		}
		else
		{
			dataIndex -= MAIN_DATABUFFER_LENGTH;
			if (_assistDataBuffer.size() < dataIndex + 1) { return; }
			if (_assistDataBuffer[dataIndex].buffer == NULL) { return; }
			dataPtr.assign(_assistDataBuffer[dataIndex]);
		}
	}

private:
	bool	clearData(ReferencedData& refData, int newDataLength);
	int		addDataToMainBuffer(char* data, int length);
	int		addDataToAssistBuffer(char* data, int length);

private:
	ReferencedData			_mainDataBuffer[MAIN_DATABUFFER_LENGTH];
	vector<ReferencedData>	_assistDataBuffer;

	PosixMutex				_mainBufferLock[MAIN_DATABUFFER_LENGTH];
	PosixMutex				_assistBufferLock;

	MemoryReleaser			_memoryReleaser;
};